package com.auto.signup.weixin.impl;

import com.auto.signup.dao.IWeixinTokenDao;
import com.auto.signup.weixin.IWeixinToken;
import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriTemplate;

import java.io.IOException;
import java.util.*;

@Component
public class WeixinToken implements IWeixinToken {

	private final static Logger logger = LoggerFactory.getLogger(WeixinToken.class);

	private final String API_AUTH = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appid}&secret={appsecret}";

	private final String JS_API_AUTH = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={token}&type=jsapi";

	@Autowired
	private RestTemplate restTemplate;
	@Autowired
	private IWeixinTokenDao weixinTokenDao;

	// private static String token = null;
	// private static String ticket = null;
	// private static long edate = 0;
	// private static long expires_in = 0;
	private static String AUTH_TOKEN_KEY = "auth-token";
	private static String JSAPI_TICKET_KEY = "jsapi-ticket";
	// private static long js_edate = 0;
	// private static long js_expires_in = 0;

	@Value("${tp.weixin.appid}")
	private String appid;
	@Value("${tp.weixin.secret}")
	private String appsecret;

	public String authToken() {
		// if (token == null) {
		// getToken();
		// } else {
		// long now = new Date().getTime() / 1000;
		// if ((edate + expires_in) <= now) {
		// getToken();
		// }
		// }
		// logger.debug("weixin token:{}", token);
		// return token;

		String token = weixinTokenDao.getToken(AUTH_TOKEN_KEY);
		if (StringUtils.isEmpty(token)) {
			token = getToken();
		}
		logger.debug("weixin token:{}", token);
		return token;
	}

	public String JsapiToken() {
		// if (ticket == null) {
		// getJsapiToken();
		// } else {
		// long now = new Date().getTime() / 1000;
		// if ((js_edate + js_expires_in) <= now) {
		// getJsapiToken();
		// }
		// }
		// logger.debug("weixin js api ticket:{}", token);
		String ticket = weixinTokenDao.getToken(JSAPI_TICKET_KEY);
		if (StringUtils.isEmpty(ticket)) {
			ticket = getJsapiToken();
		}
		logger.debug("weixin js api ticket:{}", ticket);
		return ticket;
	}

	/**
	 * noncestr=Wm3WZYTPz0wzccnW
	 * jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
	 * timestamp=1414587457 url=http://mp.weixin.qq.com?params=value
	 * 
	 * @return
	 */
	public Map<String, ?> jsApiSign(String url) {
		Map<String, String> pp = new HashMap<>();
		String nonce = RandomStringUtils.randomAlphanumeric(16);
		String timestamp = String.valueOf(new Date().getTime() / 1000);
		pp.put("noncestr", nonce);
		pp.put("jsapi_ticket", JsapiToken());
		pp.put("timestamp", timestamp);
		pp.put("url", url);

		List<String> names = new ArrayList<String>(pp.keySet());
		Collections.sort(names);
		StringBuffer buffer = new StringBuffer();
		for (String key : names) {
			buffer.append(key).append("=").append(pp.get(key)).append("&");
		}
		String sign = DigestUtils.sha1Hex(buffer.substring(0, buffer.length() - 1));

		Map<String, Object> map = new HashMap<>();
		map.put("appId", appid);
		map.put("timestamp", timestamp);
		map.put("nonceStr", nonce);
		map.put("signature", sign);
		return map;
	}

	private String getToken() {
		String token = "";
		try {
			ResponseEntity<String> json = restTemplate.getForEntity(new UriTemplate(API_AUTH).expand(appid, appsecret),
					String.class);
			if (json.getStatusCode().is2xxSuccessful()) {
				Map<String, Object> map = Jackson2ObjectMapperBuilder.json().build().readValue(json.getBody(),
						new TypeReference<Map<String, Object>>() {
						});
				if (map.get("errcode") != null) {
					logger.error("error:{}", map.get("errcode"));
				} else {
					token = Objects.toString(map.get("access_token"));
					logger.info("weixin access_token:{}", token);
					Long expires_in = Long.valueOf(Objects.toString(map.get("expires_in")));
					weixinTokenDao.save(AUTH_TOKEN_KEY, token, expires_in);
					// edate = new Date().getTime() / 1000;
				}
			} else {
				logger.error("error:{}", json.getStatusCode().getReasonPhrase());
			}

		} catch (RestClientException | IOException e) {
			logger.error("error:{}", e);
		}
		return token;
	}

	private String getJsapiToken() {
		String ticket = "";
		String x = authToken();
		try {
			ResponseEntity<String> json = restTemplate.getForEntity(new UriTemplate(JS_API_AUTH).expand(x),
					String.class);
			if (json.getStatusCode().is2xxSuccessful()) {
				Map<String, Object> map = Jackson2ObjectMapperBuilder.json().build().readValue(json.getBody(),
						new TypeReference<Map<String, Object>>() {
						});
				if (StringUtils.equals(Objects.toString(map.get("errcode")), "0")) {
					ticket = Objects.toString(map.get("ticket"));
					logger.info("weixin new ticket:{}", ticket);
					Long js_expires_in = Long.valueOf(Objects.toString(map.get("expires_in")));
					weixinTokenDao.save(JSAPI_TICKET_KEY, ticket, js_expires_in);
					// js_edate = new Date().getTime() / 1000;
				} else {

				}
			} else {
				logger.error("error:{}", json.getStatusCode().getReasonPhrase());
			}

		} catch (RestClientException | IOException e) {
			logger.error("error:{}", e);
		}
		return ticket;
	}
}
